HDU 5720 Wool(扫描线)

题意:

$给定N\le 10^5个长度为A_i\le 10^{18}的线段,现有[L, R]的区间长度的线段$
$问哪些长度不能与已有线段构成三角形$

分析:

$考虑三角形的边b,对于任意的a,那么c\in (a-b, a+b)$
$现在要贪心使得这个区间长度L=2b最大,令a\ge b,那么就选择最大的那个b$
$只要排序一波就可以得到所有的合法区间了$
$扫描线合并一波,最后ans=R-L+1-tot$
$时间复杂度O(nlogn)$

代码:

//
//  Created by TaoSama on 2016-07-20
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n;
typedef long long LL;
LL a[N], l, r;

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);
    clock_t _ = clock();

    int t; scanf("%d", &t);
    while(t--) {
        scanf("%d%I64d%I64d", &n, &l, &r);
        for(int i = 1; i <= n; ++i) scanf("%I64d", a + i);
        sort(a + 1, a + 1 + n);

        map<LL, int> mp;
        for(int i = 2; i <= n; ++i) {
            LL c = a[i] - a[i - 1] + 1;
            LL d = a[i] + a[i - 1] - 1;
            c = max(c, l); d = min(d, r);
            ++mp[c];
            --mp[d + 1];
        }

        int sum = 0;
        LL last = mp.begin()->first, ans = 0;
        for(auto& p : mp) {
            if(sum >= 1) {
                ans += p.first - last;
            }
            sum += p.second;
            last = p.first;
        }
        ans = r - l + 1 - ans;
        printf("%I64d\n", ans);
    }

#ifdef LOCAL
    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
    return 0;
}